package com.lagou.edu.server;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * Hello world!
 *
 */
public class Boostrap
{

    private Service[] services ;
    /**
    * 功能描述:minicat启动步骤
     * @author: hyw
     * @return:
     * @since: 2021/9/28 19:11
    */
    public void start() throws IOException {


        //完成xml文件的读取缓存，servlet的读取
        //doLoadServet();

        // 开启socket端口服务
        //ServerSocket serverSocket = new ServerSocket(port);

        //minicat 1.0 版本
        //需求描述：完成http://127.0.0.1:8080 访问在浏览器打印 ”Hello World!“
//        while (true){
//            Socket accept = serverSocket.accept();
//            OutputStream outputStream = accept.getOutputStream();
//            String content = "Hello World!";
//            outputStream.write((HttpProtocolUtil.getHttpHeader200(content.getBytes().length)+content).getBytes());
//            outputStream.close();
//            accept.close();
//        }


        //minicat 2.0 版本
        //需求描述，完成Request、Respose封装，完成访问 http://127.0.0.1:8080 访问html静态资源文件显示
//        while (true){
//            Socket accept = serverSocket.accept();
//            Request request = new Request(accept.getInputStream());
//            Response response = new Response(accept.getOutputStream());
//            response.outputHtml(request.getUrl());
//        }

        //minicat 3.0 版本
        //需求描述，完成动态资源的响应（servlet）
//        while (true){
//            Socket accept = serverSocket.accept();
//            Request request = new Request(accept.getInputStream());
//            Response response = new Response(accept.getOutputStream());
//            if(!cacheServlets.containsKey(request.getUrl())){
//                response.outputHtml(request.getUrl());
//            } else{
//                cacheServlets.get(request.getUrl()).service(request,response);
//            }
//
//        }


        //minicat 4.0 版本
        //需求描述，完成动态资源的响应（servlet）,解决BIO请求阻塞问题 (使用线程，非线程池)
//        while (true){
//            Socket accept = serverSocket.accept();
//            HttpServletProcessor httpServletProcessor = new HttpServletProcessor(accept, cacheServlets);
//            httpServletProcessor.start();
//        }

        //minicat 5.0 版本
        //需求描述，完成动态资源的响应（servlet）,解决BIO请求阻塞问题 (使用线程，线程池)
//        while (true){
//            Socket accept = serverSocket.accept();
//            int corePoolSize=10;//核心线程数
//            int maximumPoolSize=50;//最大线程数
//            long keepAliveTime=60;//线程活跃时间
//            TimeUnit unit=TimeUnit.SECONDS;//时间单位
//            BlockingQueue<Runnable> workQueue=new ArrayBlockingQueue<>(50);//指定线程池阻塞队列为ArrayBlockingQueue
//            ThreadFactory threadFactory=Executors.defaultThreadFactory();//线程工厂
//            RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();//线程拒绝策略
//            ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
//
//            HttpServletProcessor httpServletProcessor = new HttpServletProcessor(accept, cacheServlets);
//            threadPoolExecutor.execute(httpServletProcessor);
//        }

        //minicat 6.0 版本
        //需求描述，模拟出webapps部署效果,
        // 并实现类似Tomcat的Server、Service、Connetor（省略）、Engine（省略）、Host、Context、Warpper、Servlet、Mapper组件
        int corePoolSize=10;//核心线程数
        int maximumPoolSize=50;//最大线程数
        long keepAliveTime=60;//线程活跃时间
        TimeUnit unit=TimeUnit.SECONDS;//时间单位
        BlockingQueue<Runnable> workQueue=new ArrayBlockingQueue<>(50);//指定线程池阻塞队列为ArrayBlockingQueue
        ThreadFactory threadFactory=Executors.defaultThreadFactory();//线程工厂
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();//线程拒绝策略
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);

        try {
            doLoadServer(threadPoolExecutor);
            Server server = new Server(services);
            //初始化
            server.initInternal();
            //开启
            server.startInternal();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
    * 功能描述:解析webapps下面每个项目的web.xml文件，获取到Servlet请求与url关系
     * @author: hyw
     * @return:
     * @since: 2021/10/13 21:47
    */
    private Map<String, Mapper.MappedWrapper> doLoadServet(Context context,String webFilePath) {
        InputStream resourceAsStream = null;
        Map<String, Mapper.MappedWrapper> mappedWrappers = new HashMap<>();
        try {
            resourceAsStream = new FileInputStream(new File(webFilePath));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        SAXReader saxReader = new SAXReader();
        try {
            Document read = saxReader.read(resourceAsStream);
            Element rootElement = read.getRootElement();
            List<Element> servletElements = rootElement.selectNodes("servlet");
            for (int i = 0; i < servletElements.size(); i++) {
                Element servletNameElement = (Element)servletElements.get(i).selectSingleNode("servlet-name");
                String servletName = servletNameElement.getStringValue();
                Element servletClassElement = (Element)servletElements.get(i).selectSingleNode("servlet-class");
                String servletClass = servletClassElement.getStringValue();
                Element servletMappingElement = (Element)rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
                Element urlPatternElement = (Element)servletMappingElement.selectSingleNode("url-pattern");
                String urlPattern = urlPatternElement.getStringValue();
                mappedWrappers.put(urlPattern,new Mapper.MappedWrapper(urlPattern,new Wrapper(urlPattern,servletClass,context))) ;
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return mappedWrappers;
    }


    /**
    * 功能描述:解析server.xml，并封装到Mapper中以及Service中
     * Mapper即是能根据url逐级定位到Servlet的Wrapper中，用于实现最终调用servlet方法
     * @author: hyw
     * @return:
     * @since: 2021/10/13 21:45
    */
    private void doLoadServer(ThreadPoolExecutor threadPoolExecutor) {
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("server.xml");
        SAXReader saxReader = new SAXReader();
        try {
            Document read = saxReader.read(resourceAsStream);
            Element rootElement = read.getRootElement();
            List<Element> serviceElements = rootElement.selectNodes("Service");
            services = new Service[serviceElements.size()];
            for (int i = 0; i < serviceElements.size(); i++) {
                Element connectorElement = (Element)serviceElements.get(i).selectSingleNode("Connector");
                int port = Integer.parseInt(connectorElement.attributeValue("port"));
                Element engineElement = (Element)serviceElements.get(i).selectSingleNode("Engine");
                List<Element> hostElements = engineElement.selectNodes("Host");
                Map<String, Mapper.MappedHost> mappedHosts = new HashMap<>();
                for (int j = 0; j < hostElements.size(); j++) {
                    //使用IP:Port方式进行键值保存
                    String hostName = hostElements.get(j).attributeValue("name") + ":" + port;
                    String appBase = hostElements.get(j).attributeValue("appBase");
                    File webappsFile = new File(appBase);
                    File[] webappContexts = webappsFile.listFiles();
                    Map<String, Mapper.MappedContext> mappedContexts = new HashMap<>();
                    //Mapper.MappedContext[] mappedContexts = new Mapper.MappedContext[webappContexts.length];
                    for (int k = 0; k < webappContexts.length; k++) {
                        //创建mapperContext组件
                        Context context = new Context(webappContexts[k].getName(),webappContexts[k].getAbsolutePath());
                        //加载webapp下面项目的web.xml,并解析获取servlet映射,封转到wrapper中
                        Map<String, Mapper.MappedWrapper> mappedWrappers =doLoadServet(context,webappContexts[k].getAbsolutePath() + "/web.xml");
                        mappedContexts.put(webappContexts[k].getName(),new Mapper.MappedContext(webappContexts[k].getName(),context,mappedWrappers));
                        //mappedContexts[k] = new Mapper.MappedContext(webappContexts[i].getName(),context,mappedWrappers);
                    }
                    //创建mapperHost组件
                    Host host = new Host(hostName, appBase);
                    mappedHosts.put(hostName,new Mapper.MappedHost(hostName,host,mappedContexts));
                }//创建mapper组件
                Mapper mapper = new Mapper(mappedHosts);
                services[i] = new Service(port, threadPoolExecutor,mapper);
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }

    /**
    * 功能描述:minicat的启动入口
     * @author: hyw
     * @return:
     * @since: 2021/9/28 19:08
    */
    public static void main( String[] args )
    {
        System.out.println( "minicar start!" );
        Boostrap boostrap = new Boostrap();
        try {
            boostrap.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
